/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package pt.our.angemc.parser;


import java.io.UnsupportedEncodingException;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
import org.antlr.runtime.ANTLRStringStream;
import org.antlr.runtime.CommonTokenStream;
import org.antlr.runtime.RecognitionException;
import org.antlr.runtime.tree.CommonTreeNodeStream;
import pt.our.angemc.datatypes.Grammar;
import pt.our.angemc.datatypes.Grammar.Pair;
import pt.our.angemc.datatypes.Symbol;
import pt.our.angemc.datatypes.Terminal;
import pt.our.angemc.datatypes.TerminalType;
import pt.our.angemc.modifications.RemoveUnitaryProductions;


/**
 *
 * @author luis
 */
public class Parser2 {

    private graalLexer lexer;
    private graalParser parser;
    private graalTree walker;

    public Parser2()
    {

    }

    public String checkGrammar(String text)
    {
        String result = "";
        lexer = new graalLexer(new ANTLRStringStream(text));
        CommonTokenStream tokens = new CommonTokenStream(lexer);

        parser = new graalParser(tokens);
        try
        {
            parser.grammar_sq();
        }
        catch (Exception e) {
            result = e.getMessage();
        }

        result = Integer.toString(parser.getNumberOfSyntaxErrors());
       
       return result;
    }

    public Set<String> checkGrammarSeman(String text) throws RecognitionException
    {
        Set<String> errors = new HashSet<String>();

        Grammar g = this.getGrammar(text);
        errors = g.isEverySymbolDefined();

        return errors;
    }

    public Grammar getGrammar(String text) throws RecognitionException
    {
        Grammar g = null;

        lexer = new graalLexer(new ANTLRStringStream(text));
        CommonTokenStream tokens = new CommonTokenStream(lexer);
        parser = new graalParser(tokens);

        graalParser.grammar_sq_return r = parser.grammar_sq();
        CommonTreeNodeStream nodes = new CommonTreeNodeStream(r.getTree());

        walker = new graalTree(nodes);
        try {
            g = walker.grammar_sq();
        } catch (RecognitionException e) {
            e.printStackTrace();
        }

        return g;

    }

    public RemoveUnitaryProductions getGrammarRUP(String text) throws RecognitionException
    {
        Grammar g = getGrammar(text);

        RemoveUnitaryProductions grammarWithUnitaryProductionsRemoved = new RemoveUnitaryProductions(g.clone());
        grammarWithUnitaryProductionsRemoved.performModification();

        return grammarWithUnitaryProductionsRemoved;

    }
    
    public Grammar substitute(String text, String oldS,String newS) throws RecognitionException, Exception
    {
        Grammar g = getGrammar(text);
        int i = g.substitute(oldS, newS);

        switch(i)
        {
            case 1 : break;
            case 2 : throw new Exception("New symbol already exists");
            case 3 : throw new Exception("Old symbol doesn't exist");
            case 4 : throw new Exception("Symbols Types are mismatched");
            default : break;
        }

        return g;
    }


    public byte[] grafo(String text) throws RecognitionException, UnsupportedEncodingException
    {
        Grammar g = getGrammar(text);
        HashMap<Symbol,Pair> map =  g.getFinFout();
        GraphViz gv = new GraphViz();
        gv.addln(gv.start_graph());
        gv.addln("rankdir=BT;");
        gv.addln("node [shape=box, color=blue];");
        for(Symbol symbol : map.keySet()){

            Collection<Symbol> fi = ((Collection<Symbol>)(map.get(symbol).getFirst()));
            Collection<Symbol> fo = ((Collection<Symbol>)(map.get(symbol).getSecond()));
            int fins = fi.size();
            int fouts = fo.size();

            gv.addln(symbol.toString() +
                         " [label=\""+ symbol.toString() + "\\n I: "+fins+" O: "+fouts+"\"];");
            
            for(Symbol symb : fi){
                String next = symb.getName();

                if((symb instanceof Terminal) && ((Terminal)symb).getType().compareTo(TerminalType.OTHER) != 0 )
                {
                    
                    next = "\"" + next + "\"";
                }
                gv.addln(next + " -> " + symbol.getName() + ";" );
            } 
        }


        gv.addln(gv.end_graph());
       
        return gv.getGraph(gv.getDotSource());
    }

    

}
